home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / usenet / volume2 / nethack / part07 < prev    next >
Encoding:
Internet Message Format  |  1987-07-29  |  54.9 KB

  1. Path: uunet!seismo!columbia!rutgers!sri-spam!ames!ucbcad!zen!ucbvax!decvax!tektronix!tekgen!tekred!games-request
  2. From: games-request@tekred.TEK.COM
  3. Newsgroups: comp.sources.games
  4. Subject: v02i007:  nethack - display oriented dungeons & dragons, Part07/16
  5. Message-ID: <1449@tekred.TEK.COM>
  6. Date: 28 Jul 87 17:49:12 GMT
  7. Sender: billr@tekred.TEK.COM
  8. Lines: 2471
  9. Approved: billr@tekred.TEK.COM
  10.  
  11. Submitted by: mike@genat.UUCP (Mike Stephenson)
  12. Comp.sources.games: Volume 2, Issue 7
  13. Archive-name: nethack/Part07
  14.  
  15.  
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 7 (of 16)."
  24. # Contents:  msdos.c objnam.c potion.c unixunix.c
  25. # Wrapped by billr@tekred on Tue Jul 28 09:49:32 1987
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f msdos.c -a "${1}" != "-c" ; then 
  28.   echo shar: Will not over-write existing file \"msdos.c\"
  29. else
  30. echo shar: Extracting \"msdos.c\" \(13705 characters\)
  31. sed "s/^X//" >msdos.c <<'END_OF_msdos.c'
  32. X/*    SCCS Id: @(#)msdos.c    1.3    87/07/14
  33. X/* An assortment of MSDOS functions.
  34. X */
  35. X
  36. X#include <stdio.h>
  37. X#include "hack.h"
  38. X
  39. X#ifdef MSDOS
  40. X# include <dos.h>
  41. X
  42. Xvoid
  43. Xflushout()
  44. X{
  45. X    (void) fflush(stdout);
  46. X}
  47. X
  48. Xgetuid() {
  49. X    return 1;
  50. X}
  51. X
  52. Xchar *
  53. Xgetlogin() {
  54. X    return ((char *) NULL);
  55. X}
  56. X
  57. Xtgetch() {
  58. X    char ch, popch();
  59. X    static char DOSgetch(), BIOSgetch();
  60. X
  61. X    if (!(ch = popch())) {
  62. X# ifdef DGK
  63. X        /* BIOSgetch can use the numeric key pad on IBM compatibles. */
  64. X        if (flags.IBMBIOS)
  65. X            ch = BIOSgetch();
  66. X        else
  67. X# endif
  68. X            ch = DOSgetch();
  69. X    }
  70. X    return ((ch == '\r') ? '\n' : ch);
  71. X}
  72. X
  73. X# define DIRECT_INPUT    0x7
  74. Xstatic char
  75. XDOSgetch() {
  76. X    union REGS regs;
  77. X
  78. X    regs.h.ah = DIRECT_INPUT;
  79. X    intdos(®s, ®s);
  80. X    if (!regs.h.al) {    /* an extended code -- not yet supported */
  81. X        regs.h.ah = DIRECT_INPUT;
  82. X        intdos(®s, ®s);    /* eat the next character */
  83. X        regs.h.al = 0;        /* and return a 0 */
  84. X    }
  85. X    return (regs.h.al);
  86. X}
  87. X
  88. X
  89. X# ifdef DGK
  90. X#  include <ctype.h>
  91. X#  include <fcntl.h>
  92. X
  93. X#  define Sprintf (void) sprintf
  94. X#  define WARN 1
  95. X#  define NOWARN 0
  96. X
  97. Xstatic char *
  98. Xgetcomspec(warn) {
  99. X    return getenv("COMSPEC");
  100. X}
  101. X
  102. X#  ifdef SHELL
  103. X#   include <process.h>
  104. Xdosh() {
  105. X    extern char orgdir[];
  106. X    char *comspec;
  107. X
  108. X    if (comspec = getcomspec()) {
  109. X        settty("To return to HACK, type \"exit\" at the DOS prompt.\n");
  110. X        chdirx(orgdir, 0);
  111. X        if (spawnl(P_WAIT, comspec, comspec, NULL) < 0) {
  112. X            printf("\nCan't spawn %s !\n", comspec);
  113. X            flags.toplin = 0;
  114. X            more();
  115. X        }
  116. X        chdirx(hackdir, 0);
  117. X        start_screen();
  118. X        docrt();
  119. X    } else
  120. X        pline("No COMSPEC !?  Can't exec COMMAND.COM");
  121. X    return(0);
  122. X}
  123. X#  endif /* SHELL */
  124. X
  125. X/* Normal characters are output when the shift key is not pushed.
  126. X * Shift characters are output when either shift key is pushed.
  127. X */
  128. X#  define KEYPADHI    83
  129. X#  define KEYPADLOW    71
  130. X#  define iskeypad(x)    (KEYPADLOW <= (x) && (x) <= KEYPADHI)
  131. Xstatic struct {
  132. X    char normal, shift;
  133. X    } keypad[KEYPADHI - KEYPADLOW + 1] = {
  134. X            {'y', 'Y'},        /* 7 */
  135. X            {'k', 'K'},        /* 8 */
  136. X            {'u', 'U'},        /* 9 */
  137. X            {'m', CTRL('P')},    /* - */
  138. X            {'h', 'H'},        /* 4 */
  139. X            {'g', 'g'},        /* 5 */
  140. X            {'l', 'L'},        /* 6 */
  141. X            {'p', 'P'},        /* + */
  142. X            {'b', 'B'},        /* 1 */
  143. X            {'j', 'J'},        /* 2 */
  144. X            {'n', 'N'},        /* 3 */
  145. X            {'i', 'I'},        /* Ins */
  146. X            {'.', ':'}        /* Del */
  147. X};
  148. X
  149. X/* BIOSgetch gets keys directly with a BIOS call.
  150. X */
  151. X#  define SHIFT        (0x1 | 0x2)
  152. X#  define KEYBRD_BIOS    0x16
  153. X
  154. Xstatic char
  155. XBIOSgetch() {
  156. X    unsigned char scan, shift, ch;
  157. X    union REGS regs;
  158. X
  159. X    /* Get scan code.
  160. X     */
  161. X    regs.h.ah = 0;
  162. X    int86(KEYBRD_BIOS, ®s, ®s);
  163. X    ch = regs.h.al;
  164. X    scan = regs.h.ah;
  165. X
  166. X    /* Get shift status.
  167. X     */
  168. X    regs.h.ah = 2;
  169. X    int86(KEYBRD_BIOS, ®s, ®s);
  170. X    shift = regs.h.al;
  171. X
  172. X    /* If scan code is for the keypad, translate it.
  173. X     */
  174. X    if (iskeypad(scan)) {
  175. X        if (shift & SHIFT)
  176. X            ch = keypad[scan - KEYPADLOW].shift;
  177. X        else
  178. X            ch = keypad[scan - KEYPADLOW].normal;
  179. X    }
  180. X    return ch;
  181. X}
  182. X
  183. X/* construct the string  file.level */
  184. Xvoid
  185. Xname_file(file, level)
  186. Xchar *file;
  187. Xint level;
  188. X{
  189. X    char *tf;
  190. X    
  191. X    if (tf = rindex(file, '.'))
  192. X        Sprintf(tf+1, "%d", level);
  193. X}
  194. X
  195. X
  196. X#  define FINDFIRST    0x4E00
  197. X#  define FINDNEXT    0x4F00
  198. X#  define GETDTA    0x2F00
  199. X#  define SETFILETIME    0x5701
  200. X#  define GETSWITCHAR    0x3700
  201. X#  define FREESPACE    0x36
  202. X
  203. Xstatic char
  204. Xswitchar()
  205. X{
  206. X    union REGS regs;
  207. X
  208. X    regs.x.ax = GETSWITCHAR;
  209. X    intdos(®s, ®s);
  210. X    return regs.h.dl;
  211. X}
  212. X
  213. Xlong
  214. Xfreediskspace(path)
  215. Xchar *path;
  216. X{
  217. X    union REGS regs;
  218. X
  219. X    regs.h.ah = FREESPACE;
  220. X    if (path[0] && path[1] == ':')
  221. X        regs.h.dl = (toupper(path[0]) - 'A') + 1;
  222. X    else
  223. X        regs.h.dl = 0;
  224. X    intdos(®s, ®s);
  225. X    if (regs.x.ax == 0xFFFF)
  226. X        return -1L;        /* bad drive number */
  227. X    else
  228. X        return ((long) regs.x.bx * regs.x.cx * regs.x.ax);
  229. X}
  230. X
  231. X/* Functions to get filenames using wildcards
  232. X */
  233. Xstatic
  234. Xfindfirst(path)
  235. Xchar *path;
  236. X{
  237. X    union REGS regs;
  238. X    struct SREGS sregs;
  239. X
  240. X    regs.x.ax = FINDFIRST;
  241. X    regs.x.cx = 0;        /* normal files */
  242. X    regs.x.dx = FP_OFF(path);
  243. X    sregs.ds = FP_SEG(path);
  244. X    intdosx(®s, ®s, &sregs);
  245. X    return !regs.x.cflag;
  246. X}
  247. X
  248. Xstatic
  249. Xfindnext() {
  250. X    union REGS regs;
  251. X
  252. X    regs.x.ax = FINDNEXT;
  253. X    intdos(®s, ®s);
  254. X    return !regs.x.cflag;
  255. X}
  256. X
  257. X/* Get disk transfer area */
  258. Xstatic char *
  259. Xgetdta() {
  260. X    union REGS regs;
  261. X    struct SREGS sregs;
  262. X    char *ret;
  263. X
  264. X    regs.x.ax = GETDTA;
  265. X    intdosx(®s, ®s, &sregs);
  266. X    FP_OFF(ret) = regs.x.bx;
  267. X    FP_SEG(ret) = sregs.es;
  268. X    return ret;
  269. X}
  270. X
  271. Xlong
  272. Xfilesize(file)
  273. Xchar *file;
  274. X{
  275. X    char *dta;
  276. X
  277. X    if (findfirst(file)) {
  278. X        dta = getdta();
  279. X        return  (* (long *) (dta + 26));
  280. X    } else
  281. X        return -1L;
  282. X}
  283. X
  284. Xvoid
  285. Xeraseall(path, files)
  286. Xchar *path, *files;
  287. X{
  288. X    char *getdta(), *dta, buf[PATHLEN];
  289. X
  290. X    dta = getdta();
  291. X    Sprintf(buf, "%s%s", path, files);
  292. X    if (findfirst(buf))
  293. X        do {
  294. X            Sprintf(buf, "%s%s", path, dta + 30);
  295. X            (void) unlink(buf);
  296. X        } while (findnext());
  297. X}
  298. X
  299. X/* Rewritten for version 3.3 to be faster
  300. X */
  301. Xvoid
  302. Xcopybones(mode) {
  303. X    char from[PATHLEN], to[PATHLEN], last[13], copy[8];
  304. X    char *frompath, *topath, *dta, *comspec;
  305. X    int status;
  306. X    long fs;
  307. X    extern saveprompt;
  308. X
  309. X    if (!ramdisk)
  310. X        return;
  311. X
  312. X    /* Find the name of the last file to be transferred
  313. X     */
  314. X    frompath = (mode != TOPERM) ? permbones : levels;
  315. X    dta = getdta();
  316. X    last[0] = '\0';
  317. X    Sprintf(from, "%s%s", frompath, allbones);
  318. X    if (findfirst(from))
  319. X        do {
  320. X            strcpy(last, dta + 30);
  321. X        } while (findnext());
  322. X
  323. X    topath = (mode == TOPERM) ? permbones : levels;
  324. X    if (last[0]) {
  325. X        Sprintf(copy, "%cC copy", switchar());
  326. X
  327. X        /* Remove any bones files in `to' directory.
  328. X         */
  329. X        eraseall(topath, allbones);
  330. X
  331. X        /* Copy `from' to `to' */
  332. X        Sprintf(to, "%s%s", topath, allbones);
  333. X        comspec = getcomspec();
  334. X        status =spawnl(P_WAIT, comspec, comspec, copy, from,
  335. X            to, "> nul", NULL);
  336. X    } else
  337. X        return;
  338. X
  339. X    /* See if the last file got there.  If so, remove the ramdisk bones
  340. X     * files.
  341. X     */
  342. X    Sprintf(to, "%s%s", topath, last);
  343. X    if (findfirst(to)) {
  344. X        if (mode == TOPERM)
  345. X            eraseall(frompath, allbones);
  346. X        return;
  347. X    }
  348. X
  349. X    /* Last file didn't get there.
  350. X     */
  351. X    Sprintf(to, "%s%s", topath, allbones);
  352. X    msmsg("Cannot copy `%s' to `%s' -- %s\n", from, to,
  353. X        (status < 0) ? "can't spawn COMSPEC !" :
  354. X        (freediskspace(topath) < filesize(from)) ?
  355. X            "insufficient disk space." : "bad path(s)?");
  356. X    if (mode == TOPERM) {
  357. X        msmsg("Bones will be left in `%s'\n",
  358. X            *levels ? levels : hackdir);
  359. X        return;
  360. X    } else {
  361. X        /* Remove all bones files on the RAMdisk */
  362. X        eraseall(levels, allbones);
  363. X        playwoRAMdisk();
  364. X    }
  365. X}
  366. X
  367. XplaywoRAMdisk() {
  368. X    msmsg("Do you wish to play without a RAMdisk (y/n) ? ");
  369. X
  370. X    /* Set ramdisk false *before* exit'ing (because msexit calls
  371. X     * copybones)
  372. X     */
  373. X    ramdisk = FALSE;
  374. X    if (getchar() != 'y') {
  375. X        settty("Be seeing you ...\n");
  376. X        exit(0);
  377. X    }
  378. X    set_lock_and_bones();
  379. X    return;
  380. X}
  381. X
  382. XsaveDiskPrompt(start) {
  383. X    extern saveprompt;
  384. X    char buf[BUFSIZ], *bp;
  385. X    int fd;
  386. X
  387. X    if (saveprompt) {
  388. X        /* Don't prompt if you can find the save file */
  389. X        if ((fd = open(SAVEF, 0)) >= 0) {
  390. X            (void) close(fd);
  391. X            return 1;
  392. X        }
  393. X        remember_topl();
  394. X        home();
  395. X        cl_end();
  396. X        msmsg("If save file is on a SAVE disk, put that disk in now.\n");
  397. X        cl_end();
  398. X        msmsg("File name (default `%s'%s) ? ", SAVEF,
  399. X            start ? "" : ", <Esc> cancels save");
  400. X        getlin(buf);
  401. X        home();
  402. X        cl_end();
  403. X        curs(1, 2);
  404. X        cl_end();
  405. X        if (!start && *buf == '\033')
  406. X            return 0;
  407. X
  408. X        /* Strip any whitespace. Also, if nothing was entered except
  409. X         * whitespace, do not change the value of SAVEF.
  410. X         */
  411. X        for (bp = buf; *bp; bp++)
  412. X            if (!isspace(*bp)) {
  413. X                strncpy(SAVEF, bp, PATHLEN);
  414. X                break;
  415. X            }
  416. X    }
  417. X    return 1;
  418. X}
  419. X
  420. X/* Return 1 if the record file was found */
  421. Xstatic
  422. Xrecord_exists() {
  423. X    int fd;
  424. X
  425. X    if ((fd = open(RECORD, 0)) >= 0) {
  426. X        close(fd);
  427. X        return TRUE;
  428. X    }
  429. X    return FALSE;
  430. X}
  431. X
  432. X/* Return 1 if the comspec was found */
  433. Xstatic
  434. Xcomspec_exists() {
  435. X    int fd;
  436. X    char *comspec;
  437. X
  438. X    if (comspec = getcomspec())
  439. X        if ((fd = open(comspec, 0)) >= 0) {
  440. X            close(fd);
  441. X            return TRUE;
  442. X        }
  443. X    return FALSE;
  444. X}
  445. X
  446. X/* Prompt for game disk, then check for record file.
  447. X */
  448. Xvoid
  449. XgameDiskPrompt() {
  450. X    extern saveprompt;
  451. X
  452. X    if (saveprompt) {
  453. X        if (record_exists() && comspec_exists())
  454. X            return;
  455. X        (void) putchar('\n');
  456. X        getreturn("when the GAME disk has been put in");
  457. X    }
  458. X    if (comspec_exists() && record_exists())
  459. X        return;
  460. X
  461. X    if (!comspec_exists())
  462. X        msmsg("\n\nWARNING: can't find comspec `%s'!\n", getcomspec());
  463. X    if (!record_exists())
  464. X        msmsg("\n\nWARNING: can't find record file `%s'!\n", RECORD);
  465. X    msmsg("If the GAME disk is not in, put it in now.\n");
  466. X    getreturn("to continue");
  467. X}
  468. X
  469. X/* Read configuration */
  470. Xvoid
  471. Xread_config_file() {
  472. X    char    tmp_ramdisk[PATHLEN], tmp_levels[PATHLEN];
  473. X    char    buf[BUFSZ], *bufp;
  474. X    FILE    *fp, *fopenp();
  475. X    extern    char plname[];
  476. X    extern    int saveprompt;
  477. X
  478. X    tmp_ramdisk[0] = 0;
  479. X    tmp_levels[0] = 0;
  480. X    if ((fp = fopenp(configfile, "r")) == NULL) {
  481. X        msmsg("Warning: no configuration file!\n");
  482. X        getreturn("to continue");
  483. X        return;
  484. X    }
  485. X    while (fgets(buf, BUFSZ, fp)) {
  486. X        if (*buf == '#')
  487. X            continue;
  488. X
  489. X        /* remove trailing whitespace
  490. X         */
  491. X        bufp = index(buf, '\n');
  492. X        while (bufp > buf && isspace(*bufp))
  493. X            bufp--;
  494. X        if (bufp == buf)
  495. X            continue;        /* skip all-blank lines */
  496. X        else
  497. X            *(bufp + 1) = 0;    /* 0 terminate line */
  498. X
  499. X        /* find the '=' */
  500. X        if (!(bufp = strchr(buf, '='))) {
  501. X            msmsg("Bad option line: '%s'\n", buf);
  502. X            getreturn("to continue");
  503. X            continue;
  504. X        }
  505. X        
  506. X        /* skip  whitespace between '=' and value */
  507. X        while (isspace(*++bufp))
  508. X            ;
  509. X
  510. X        /* Go through possible variables */
  511. X        if (!strncmp(buf, "HACKDIR", 4)) {
  512. X            strncpy(hackdir, bufp, PATHLEN);
  513. X        
  514. X        } else if (!strncmp(buf, "RAMDISK", 3)) {
  515. X            strncpy(tmp_ramdisk, bufp, PATHLEN);
  516. X
  517. X        } else if (!strncmp(buf, "LEVELS", 4)) {
  518. X            strncpy(tmp_levels, bufp, PATHLEN);
  519. X
  520. X        } else if (!strncmp(buf, "OPTIONS", 4)) {
  521. X            parseoptions(bufp, TRUE);
  522. X            if (plname[0])        /* If a name was given */
  523. X                plnamesuffix();    /* set the character class */
  524. X
  525. X        } else if (!strncmp(buf, "SAVE", 4)) {
  526. X            char *ptr;
  527. X            if (ptr = index(bufp, ';')) {
  528. X                *ptr = '\0';
  529. X                if (*(ptr+1) == 'n' || *(ptr+1) == 'N')
  530. X                    saveprompt = FALSE;
  531. X            }
  532. X            (void) strncpy(SAVEF, bufp, PATHLEN);
  533. X            append_slash(SAVEF);
  534. X
  535. X        } else if (!strncmp(buf, "GRAPHICS", 4)) {
  536. X            struct symbols s;
  537. X
  538. X            if (sscanf(bufp, "%u%u%u%u%u%u%u%u%u", &s.vwall,
  539. X                    &s.hwall, &s.tlcorn, &s.trcorn, &s.blcorn,
  540. X                    &s.brcorn, &s.door, &s.room, &s.corr) == 9)
  541. X                symbol = s;
  542. X            else {
  543. X                msmsg("GRAPHICS did not contain 9 values\n");
  544. X                getreturn("to continue");
  545. X            }
  546. X        } else {
  547. X            msmsg("Bad option line: '%s'\n", buf);
  548. X            getreturn("to continue");
  549. X        }
  550. X    }
  551. X    fclose(fp);
  552. X
  553. X    strcpy(permbones, tmp_levels);
  554. X    if (tmp_ramdisk[0]) {
  555. X        strcpy(levels, tmp_ramdisk);
  556. X        if (strcmpi(permbones, levels))        /* if not identical */
  557. X            ramdisk = TRUE;
  558. X    } else
  559. X        strcpy(levels, tmp_levels);
  560. X    strcpy(bones, levels);
  561. X}
  562. X
  563. X/* Set names for bones[] and lock[]
  564. X */
  565. Xvoid
  566. Xset_lock_and_bones() {
  567. X    if (!ramdisk) {
  568. X        strcpy(levels, permbones);
  569. X        strcpy(bones, permbones);
  570. X    }
  571. X    append_slash(permbones);
  572. X    append_slash(levels);
  573. X    append_slash(bones);
  574. X    strcat(bones, allbones);
  575. X    strcpy(lock, levels);
  576. X    strcat(lock, alllevels);
  577. X}
  578. X
  579. X/* Add a backslash to any name not ending in /, \ or :   There must
  580. X * be room for the \
  581. X */
  582. Xvoid
  583. Xappend_slash(name)
  584. Xchar *name;
  585. X{
  586. X    char *ptr;
  587. X
  588. X    if (!*name)
  589. X        return;
  590. X    ptr = name + (strlen(name) - 1);
  591. X    if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
  592. X        *++ptr = '\\';
  593. X        *++ptr = '\0';
  594. X    }
  595. X}
  596. X
  597. X
  598. Xvoid
  599. Xgetreturn(str)
  600. Xchar *str;
  601. X{
  602. X    int ch;
  603. X
  604. X    msmsg("Hit <RETURN> %s.", str);
  605. X    while ((ch = getchar()) != '\n')
  606. X        ;
  607. X}
  608. X
  609. Xvoid
  610. Xmsmsg(fmt, a1, a2, a3)
  611. Xchar *fmt;
  612. Xlong a1, a2, a3;
  613. X{
  614. X    printf(fmt, a1, a2, a3);
  615. X    flushout();
  616. X}
  617. X
  618. X/* Chdrive() changes the default drive.
  619. X */
  620. X#define SELECTDISK    0x0E
  621. Xvoid
  622. Xchdrive(str)
  623. Xchar *str;
  624. X{
  625. X    char *ptr;
  626. X    union REGS inregs;
  627. X    char drive;
  628. X
  629. X    if ((ptr = index(str, ':')) != NULL) {
  630. X        drive = toupper(*(ptr - 1));
  631. X        inregs.h.ah = SELECTDISK;
  632. X        inregs.h.dl = drive - 'A';
  633. X        intdos(&inregs, &inregs);
  634. X    }
  635. X}
  636. X
  637. X/* Use the IOCTL DOS function call to change stdin and stdout to raw
  638. X * mode.  For stdin, this prevents MSDOS from trapping ^P, thus
  639. X * freeing us of ^P toggling 'echo to printer'.
  640. X * Thanks to Mark Zbikowski (markz@microsoft.UUCP).
  641. X */
  642. X
  643. X#  define DEVICE    0x80
  644. X#  define RAW        0x20
  645. X#  define IOCTL        0x44
  646. X#  define STDIN        fileno(stdin)
  647. X#  define STDOUT    fileno(stdout)
  648. X#  define GETBITS    0
  649. X#  define SETBITS    1
  650. X
  651. Xstatic unsigned    old_stdin, old_stdout, ioctl();
  652. X
  653. Xdisable_ctrlP() {
  654. X    if (!flags.rawio)
  655. X        return;
  656. X    old_stdin = ioctl(STDIN, GETBITS, 0);
  657. X    old_stdout = ioctl(STDOUT, GETBITS, 0);
  658. X    if (old_stdin & DEVICE)
  659. X        ioctl(STDIN, SETBITS, old_stdin | RAW);
  660. X    if (old_stdout & DEVICE)
  661. X        ioctl(STDOUT, SETBITS, old_stdout | RAW);
  662. X}
  663. X
  664. Xenable_ctrlP() {
  665. X    if (!flags.rawio)
  666. X        return;
  667. X    if (old_stdin)
  668. X        (void) ioctl(STDIN, SETBITS, old_stdin);
  669. X    if (old_stdout)
  670. X        (void) ioctl(STDOUT, SETBITS, old_stdout);
  671. X}
  672. X
  673. Xstatic unsigned
  674. Xioctl(handle, mode, setvalue)
  675. Xunsigned setvalue;
  676. X{
  677. X    union REGS regs;
  678. X
  679. X    regs.h.ah = IOCTL;
  680. X    regs.h.al = mode;
  681. X    regs.x.bx = handle;
  682. X    regs.h.dl = setvalue;
  683. X    regs.h.dh = 0;            /* Zero out dh */
  684. X    intdos(®s, ®s);
  685. X    return (regs.x.dx);
  686. X}
  687. X
  688. X/* Follow the PATH, trying to fopen the file.
  689. X */
  690. X#define PATHSEP    ';'
  691. X
  692. XFILE *
  693. Xfopenp(name, mode)
  694. Xchar *name, *mode;
  695. X{
  696. X    char buf[BUFSIZ], *bp, *pp, *getenv(), lastch;
  697. X    FILE *fp;
  698. X
  699. X    /* Try the default directory first.  Then look along PATH.
  700. X     */
  701. X    strcpy(buf, name);
  702. X    if (fp = fopen(buf, mode))
  703. X        return fp;
  704. X    else {
  705. X        pp = getenv("PATH");
  706. X        while (pp && *pp) {
  707. X            bp = buf;
  708. X            while (*pp && *pp != PATHSEP)
  709. X                lastch = *bp++ = *pp++;
  710. X            if (lastch != '\\' && lastch != '/')
  711. X                *bp++ = '\\';
  712. X            strcpy(bp, name);
  713. X            if (fp = fopen(buf, mode))
  714. X                return fp;
  715. X            if (*pp)
  716. X                pp++;
  717. X        }
  718. X    }
  719. X    return NULL;
  720. X}
  721. X# endif /* DGK */
  722. X
  723. X/* Chdir back to original directory
  724. X */
  725. X# undef exit
  726. Xvoid
  727. Xmsexit(code)
  728. X{
  729. X# ifdef CHDIR
  730. X    extern char orgdir[];
  731. X# endif
  732. X
  733. X# ifdef DGK
  734. X    flushout();
  735. X    enable_ctrlP();        /* in case this wasn't done */
  736. X    if (ramdisk)
  737. X        copybones(TOPERM);
  738. X# endif
  739. X# ifdef CHDIR
  740. X    chdir(orgdir);        /* chdir, not chdirx */
  741. X#  ifdef DGK
  742. X    chdrive(orgdir);
  743. X#  endif
  744. X# endif
  745. X    exit(code);
  746. X}
  747. X#endif /* MSDOS */
  748. END_OF_msdos.c
  749. if test 13705 -ne `wc -c <msdos.c`; then
  750.     echo shar: \"msdos.c\" unpacked with wrong size!
  751. fi
  752. # end of overwriting check
  753. fi
  754. if test -f objnam.c -a "${1}" != "-c" ; then 
  755.   echo shar: Will not over-write existing file \"objnam.c\"
  756. else
  757. echo shar: Extracting \"objnam.c\" \(13414 characters\)
  758. sed "s/^X//" >objnam.c <<'END_OF_objnam.c'
  759. X/*    SCCS Id: @(#)objnam.c    1.3    87/07/14
  760. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  761. X/* objnam.c - version 1.0.2 */
  762. X
  763. X#include    "hack.h"
  764. X#define Sprintf (void) sprintf
  765. X#define Strcat  (void) strcat
  766. X#define    Strcpy    (void) strcpy
  767. X#define    PREFIX    15
  768. Xextern char *eos();
  769. Xextern int bases[];
  770. X
  771. Xchar *
  772. Xstrprepend(s,pref) register char *s, *pref; {
  773. Xregister int i = strlen(pref);
  774. X    if(i > PREFIX) {
  775. X        pline("WARNING: prefix too short.");
  776. X        return(s);
  777. X    }
  778. X    s -= i;
  779. X    (void) strncpy(s, pref, i);    /* do not copy trailing 0 */
  780. X    return(s);
  781. X}
  782. X
  783. Xchar *
  784. Xsitoa(a) int a; {
  785. Xstatic char buf[13];
  786. X    Sprintf(buf, (a < 0) ? "%d" : "+%d", a);
  787. X    return(buf);
  788. X}
  789. X
  790. Xchar *
  791. Xtypename(otyp)
  792. Xregister int otyp;
  793. X{
  794. Xstatic char buf[BUFSZ];
  795. Xregister struct objclass *ocl = &objects[otyp];
  796. Xregister char *an = ocl->oc_name;
  797. Xregister char *dn = ocl->oc_descr;
  798. Xregister char *un = ocl->oc_uname;
  799. Xregister int nn = ocl->oc_name_known;
  800. X    switch(ocl->oc_olet) {
  801. X    case POTION_SYM:
  802. X        Strcpy(buf, "potion");
  803. X        break;
  804. X    case SCROLL_SYM:
  805. X        Strcpy(buf, "scroll");
  806. X        break;
  807. X    case WAND_SYM:
  808. X        Strcpy(buf, "wand");
  809. X        break;
  810. X#ifdef SPELLS
  811. X    case SPBOOK_SYM:
  812. X        Strcpy(buf, "spellbook");
  813. X        break;
  814. X#endif
  815. X    case RING_SYM:
  816. X        Strcpy(buf, "ring");
  817. X        break;
  818. X    default:
  819. X        if(nn) {
  820. X            Strcpy(buf, an);
  821. X            if(otyp >= TURQUOISE && otyp <= JADE)
  822. X                Strcat(buf, " stone");
  823. X            if(un)
  824. X                Sprintf(eos(buf), " called %s", un);
  825. X            if(dn)
  826. X                Sprintf(eos(buf), " (%s)", dn);
  827. X        } else {
  828. X            Strcpy(buf, dn ? dn : an);
  829. X            if(ocl->oc_olet == GEM_SYM)
  830. X                Strcat(buf, " gem");
  831. X            if(un)
  832. X                Sprintf(eos(buf), " called %s", un);
  833. X        }
  834. X        return(buf);
  835. X    }
  836. X    /* here for ring/scroll/potion/wand */
  837. X    if(nn)
  838. X        Sprintf(eos(buf), " of %s", an);
  839. X    if(un)
  840. X        Sprintf(eos(buf), " called %s", un);
  841. X    if(dn)
  842. X        Sprintf(eos(buf), " (%s)", dn);
  843. X    return(buf);
  844. X}
  845. X
  846. Xchar *
  847. Xxname(obj)
  848. Xregister struct obj *obj;
  849. X{
  850. Xstatic char bufr[BUFSZ];
  851. Xregister char *buf = &(bufr[PREFIX]);    /* leave room for "17 -3 " */
  852. Xregister int nn = objects[obj->otyp].oc_name_known;
  853. Xregister char *an = objects[obj->otyp].oc_name;
  854. Xregister char *dn = objects[obj->otyp].oc_descr;
  855. Xregister char *un = objects[obj->otyp].oc_uname;
  856. Xregister int pl = (obj->quan != 1);
  857. X#ifdef KAA
  858. X    if(!obj->dknown && !Blind && obj->olet != WEAPON_SYM) obj->dknown=1;
  859. X#else
  860. X    if(!obj->dknown && !Blind) obj->dknown = 1; /* %% doesnt belong here */
  861. X#endif
  862. X    switch(obj->olet) {
  863. X    case AMULET_SYM:
  864. X        Strcpy(buf, (obj->spe < 0 && obj->known)
  865. X            ? "cheap plastic imitation of the " : "");
  866. X        Strcat(buf,"Amulet of Yendor");
  867. X        break;
  868. X    case TOOL_SYM:
  869. X        if(!nn) {
  870. X            Strcpy(buf, dn);
  871. X            break;
  872. X        }
  873. X        Strcpy(buf,an);
  874. X        break;
  875. X    case FOOD_SYM:
  876. X        if(obj->otyp == DEAD_HOMUNCULUS && pl) {
  877. X            pl = 0;
  878. X            Strcpy(buf, "dead homunculi");
  879. X            break;
  880. X        }
  881. X        /* fungis ? */
  882. X#ifdef KAA /* The fungus mistake was a D&D holdover. */
  883. X        if(obj->otyp == DEAD_VIOLET_FUNGUS && pl) {
  884. X            pl = 0;
  885. X            Strcpy(buf, "dead violet fungi");
  886. X            break;
  887. X        }
  888. X#endif
  889. X        /* fall into next case */
  890. X    case WEAPON_SYM:
  891. X        if(obj->otyp == WORM_TOOTH && pl) {
  892. X            pl = 0;
  893. X            Strcpy(buf, "worm teeth");
  894. X            break;
  895. X        }
  896. X        if(obj->otyp == CRYSKNIFE && pl) {
  897. X            pl = 0;
  898. X            Strcpy(buf, "crysknives");
  899. X            break;
  900. X        }
  901. X        /* fall into next case */
  902. X    case ARMOR_SYM:
  903. X    case CHAIN_SYM:
  904. X    case ROCK_SYM:
  905. X        Strcpy(buf,an);
  906. X        break;
  907. X    case BALL_SYM:
  908. X        Sprintf(buf, "%sheavy iron ball",
  909. X          (obj->owt > objects[obj->otyp].oc_weight) ? "very " : "");
  910. X        break;
  911. X    case POTION_SYM:
  912. X        if(nn || un || !obj->dknown) {
  913. X            Strcpy(buf, "potion");
  914. X            if(pl) {
  915. X                pl = 0;
  916. X                Strcat(buf, "s");
  917. X            }
  918. X            if(!obj->dknown) break;
  919. X            if(un) {
  920. X                Strcat(buf, " called ");
  921. X                Strcat(buf, un);
  922. X            } else {
  923. X                Strcat(buf, " of ");
  924. X                Strcat(buf, an);
  925. X            }
  926. X        } else {
  927. X            Strcpy(buf, dn);
  928. X            Strcat(buf, " potion");
  929. X        }
  930. X        break;
  931. X    case SCROLL_SYM:
  932. X        Strcpy(buf, "scroll");
  933. X        if(pl) {
  934. X            pl = 0;
  935. X            Strcat(buf, "s");
  936. X        }
  937. X        if(!obj->dknown) break;
  938. X        if(nn) {
  939. X            Strcat(buf, " of ");
  940. X            Strcat(buf, an);
  941. X        } else if(un) {
  942. X            Strcat(buf, " called ");
  943. X            Strcat(buf, un);
  944. X        } else {
  945. X            Strcat(buf, " labeled ");
  946. X            Strcat(buf, dn);
  947. X        }
  948. X        break;
  949. X    case WAND_SYM:
  950. X        if(!obj->dknown)
  951. X            Sprintf(buf, "wand");
  952. X        else if(nn)
  953. X            Sprintf(buf, "wand of %s", an);
  954. X        else if(un)
  955. X            Sprintf(buf, "wand called %s", un);
  956. X        else
  957. X            Sprintf(buf, "%s wand", dn);
  958. X        break;
  959. X#ifdef SPELLS
  960. X    case SPBOOK_SYM:
  961. X        if(!obj->dknown)
  962. X            Sprintf(buf, "spellbook");
  963. X        else if(nn)
  964. X            Sprintf(buf, "spellbook of %s", an);
  965. X        else if(un)
  966. X            Sprintf(buf, "spellbook called %s", un);
  967. X        else
  968. X            Sprintf(buf, "%s spellbook", dn);
  969. X        break;
  970. X#endif
  971. X    case RING_SYM:
  972. X        if(!obj->dknown)
  973. X            Sprintf(buf, "ring");
  974. X        else if(nn)
  975. X            Sprintf(buf, "ring of %s", an);
  976. X        else if(un)
  977. X            Sprintf(buf, "ring called %s", un);
  978. X        else
  979. X            Sprintf(buf, "%s ring", dn);
  980. X        break;
  981. X    case GEM_SYM:
  982. X        if(!obj->dknown) {
  983. X            Strcpy(buf, "gem");
  984. X            break;
  985. X        }
  986. X        if(!nn) {
  987. X#ifdef KAA
  988. X            if(un) {
  989. X                if (!pl)  Sprintf(buf,"gem called %s",un);
  990. X                else      Sprintf(buf,"gems called %s",un);
  991. X                pl=0;
  992. X            } else
  993. X#endif
  994. X                Sprintf(buf, "%s gem", dn);
  995. X            break;
  996. X        }
  997. X        Strcpy(buf, an);
  998. X        if(obj->otyp >= TURQUOISE && obj->otyp <= JADE)
  999. X            Strcat(buf, " stone");
  1000. X        break;
  1001. X    default:
  1002. X        Sprintf(buf,"glorkum %c (0%o) %u %d",
  1003. X            obj->olet,obj->olet,obj->otyp,obj->spe);
  1004. X    }
  1005. X    if(pl) {
  1006. X        register char *p;
  1007. X
  1008. X        for(p = buf; *p; p++) {
  1009. X            if(!strncmp(" of ", p, 4)) {
  1010. X                /* pieces of, cloves of, lumps of */
  1011. X                register int c1, c2 = 's';
  1012. X
  1013. X                do {
  1014. X                    c1 = c2; c2 = *p; *p++ = c1;
  1015. X                } while(c1);
  1016. X                goto nopl;
  1017. X            }
  1018. X        }
  1019. X        p = eos(buf)-1;
  1020. X        if(*p == 's' || *p == 'z' || *p == 'x' ||
  1021. X            (*p == 'h' && p[-1] == 's'))
  1022. X            Strcat(buf, "es");    /* boxes */
  1023. X        else if(*p == 'y' && !index(vowels, p[-1]))
  1024. X            Strcpy(p, "ies");    /* rubies, zruties */
  1025. X        else
  1026. X            Strcat(buf, "s");
  1027. X    }
  1028. Xnopl:
  1029. X    if(obj->onamelth) {
  1030. X        Strcat(buf, " named ");
  1031. X        Strcat(buf, ONAME(obj));
  1032. X    }
  1033. X    return(buf);
  1034. X}
  1035. X
  1036. Xchar *
  1037. Xdoname(obj)
  1038. Xregister struct obj *obj;
  1039. X{
  1040. Xchar prefix[PREFIX];
  1041. Xregister char *bp = xname(obj);
  1042. X    if(obj->quan != 1)
  1043. X        Sprintf(prefix, "%u ", obj->quan);
  1044. X    else
  1045. X        Strcpy(prefix, "a ");
  1046. X    switch(obj->olet) {
  1047. X    case AMULET_SYM:
  1048. X        if(strncmp(bp, "cheap ", 6))
  1049. X            Strcpy(prefix, "the ");
  1050. X        break;
  1051. X    case ARMOR_SYM:
  1052. X        if(obj->owornmask & W_ARMOR)
  1053. X            Strcat(bp, " (being worn)");
  1054. X        /* fall into next case */
  1055. X    case WEAPON_SYM:
  1056. X        if(obj->known) {
  1057. X#ifdef KAA
  1058. X            /* dknown is special for weapons */
  1059. X            if(obj->dknown && obj->olet == WEAPON_SYM)
  1060. X                Strcat(prefix,"blessed ");
  1061. X#endif
  1062. X            Strcat(prefix, sitoa(obj->spe));
  1063. X            Strcat(prefix, " ");
  1064. X        }
  1065. X        break;
  1066. X#ifdef MARKER
  1067. X    case TOOL_SYM:            /* temp. hack by GAN 11/18/86 */
  1068. X        if(obj->otyp != MAGIC_MARKER) break;
  1069. X#endif
  1070. X    case WAND_SYM:
  1071. X        if(obj->known)
  1072. X            Sprintf(eos(bp), " (%d)", obj->spe);
  1073. X        break;
  1074. X    case RING_SYM:
  1075. X        if(obj->owornmask & W_RINGR) Strcat(bp, " (on right hand)");
  1076. X        if(obj->owornmask & W_RINGL) Strcat(bp, " (on left hand)");
  1077. X        if(obj->known && (objects[obj->otyp].bits & SPEC)) {
  1078. X            Strcat(prefix, sitoa(obj->spe));
  1079. X            Strcat(prefix, " ");
  1080. X        }
  1081. X        break;
  1082. X    }
  1083. X    if(obj->owornmask & W_WEP)
  1084. X        Strcat(bp, " (weapon in hand)");
  1085. X    if(obj->unpaid)
  1086. X        Strcat(bp, " (unpaid)");
  1087. X    if(!strcmp(prefix, "a ") && index(vowels, *bp))
  1088. X        Strcpy(prefix, "an ");
  1089. X    bp = strprepend(bp, prefix);
  1090. X    return(bp);
  1091. X}
  1092. X
  1093. X/* used only in fight.c (thitu) */
  1094. Xsetan(str,buf)
  1095. Xregister char *str,*buf;
  1096. X{
  1097. X    if(index(vowels,*str))
  1098. X        Sprintf(buf, "an %s", str);
  1099. X    else
  1100. X        Sprintf(buf, "a %s", str);
  1101. X}
  1102. X
  1103. Xchar *
  1104. Xaobjnam(otmp,verb) register struct obj *otmp; register char *verb; {
  1105. Xregister char *bp = xname(otmp);
  1106. Xchar prefix[PREFIX];
  1107. X    if(otmp->quan != 1) {
  1108. X        Sprintf(prefix, "%u ", otmp->quan);
  1109. X        bp = strprepend(bp, prefix);
  1110. X    }
  1111. X
  1112. X    if(verb) {
  1113. X        /* verb is given in plural (i.e., without trailing s) */
  1114. X        Strcat(bp, " ");
  1115. X        if(otmp->quan != 1)
  1116. X            Strcat(bp, verb);
  1117. X        else if(!strcmp(verb, "are"))
  1118. X            Strcat(bp, "is");
  1119. X        else {
  1120. X            Strcat(bp, verb);
  1121. X            Strcat(bp, "s");
  1122. X        }
  1123. X    }
  1124. X    return(bp);
  1125. X}
  1126. X
  1127. Xchar *
  1128. XDoname(obj)
  1129. Xregister struct obj *obj;
  1130. X{
  1131. X    register char *s = doname(obj);
  1132. X
  1133. X    if('a' <= *s && *s <= 'z') *s -= ('a' - 'A');
  1134. X    return(s);
  1135. X}
  1136. X
  1137. Xchar *wrp[] = {    "wand", "ring", "potion", "scroll", "gem"
  1138. X#ifdef SPELLS
  1139. X        , "spellbook"
  1140. X#endif
  1141. X          };
  1142. Xchar wrpsym[] = { WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM
  1143. X#ifdef SPELLS
  1144. X          , SPBOOK_SYM
  1145. X#endif
  1146. X        };
  1147. X
  1148. Xstruct obj *
  1149. Xreadobjnam(bp) register char *bp; {
  1150. Xregister char *p;
  1151. Xregister int i;
  1152. Xint cnt, spe, spesgn, typ, heavy;
  1153. Xchar let;
  1154. Xchar *un, *dn, *an;
  1155. X#ifdef KAA
  1156. Xint blessed=0;
  1157. X#endif
  1158. X/* int the = 0; char *oname = 0; */
  1159. X    cnt = spe = spesgn = typ = heavy = 0;
  1160. X    let = 0;
  1161. X    an = dn = un = 0;
  1162. X    for(p = bp; *p; p++)    /* set the string to lower case */
  1163. X        if('A' <= *p && *p <= 'Z') *p += 'a'-'A';
  1164. X    if(!strncmp(bp, "the ", 4)){
  1165. X/*        the = 1; */
  1166. X        bp += 4;
  1167. X    } else if(!strncmp(bp, "an ", 3)){
  1168. X        cnt = 1;
  1169. X        bp += 3;
  1170. X    } else if(!strncmp(bp, "a ", 2)){
  1171. X        cnt = 1;
  1172. X        bp += 2;
  1173. X    }
  1174. X#ifdef KAA
  1175. X    if(!strncmp(bp,"blessed ",8)) {
  1176. X        blessed=1;
  1177. X        bp += 8;
  1178. X    }
  1179. X#endif
  1180. X    if(!cnt && digit(*bp)){
  1181. X        cnt = atoi(bp);
  1182. X        while(digit(*bp)) bp++;
  1183. X        while(*bp == ' ') bp++;
  1184. X    }
  1185. X    if(!cnt) cnt = 1;        /* %% what with "gems" etc. ? */
  1186. X
  1187. X    if(*bp == '+' || *bp == '-'){
  1188. X        spesgn = (*bp++ == '+') ? 1 : -1;
  1189. X        spe = atoi(bp);
  1190. X        while(digit(*bp)) bp++;
  1191. X        while(*bp == ' ') bp++;
  1192. X    } else {
  1193. X        p = rindex(bp, '(');
  1194. X        if(p) {
  1195. X            if(p > bp && p[-1] == ' ') p[-1] = 0;
  1196. X            else *p = 0;
  1197. X            p++;
  1198. X            spe = atoi(p);
  1199. X            while(digit(*p)) p++;
  1200. X            if(strcmp(p, ")")) spe = 0;
  1201. X            else spesgn = 1;
  1202. X        }
  1203. X    }
  1204. X    /* now we have the actual name, as delivered by xname, say
  1205. X        green potions called whisky
  1206. X        scrolls labeled "QWERTY"
  1207. X        egg
  1208. X        dead zruties
  1209. X        fortune cookies
  1210. X        very heavy iron ball named hoei
  1211. X        wand of wishing
  1212. X        elven cloak
  1213. X    */
  1214. X    for(p = bp; *p; p++) if(!strncmp(p, " named ", 7)) {
  1215. X        *p = 0;
  1216. X/*        oname = p+7; */
  1217. X    }
  1218. X    for(p = bp; *p; p++) if(!strncmp(p, " called ", 8)) {
  1219. X        *p = 0;
  1220. X        un = p+8;
  1221. X    }
  1222. X    for(p = bp; *p; p++) if(!strncmp(p, " labeled ", 9)) {
  1223. X        *p = 0;
  1224. X        dn = p+9;
  1225. X    }
  1226. X
  1227. X    /* first change to singular if necessary */
  1228. X    if(cnt != 1) {
  1229. X        /* find "cloves of garlic", "worthless pieces of blue glass" */
  1230. X        for(p = bp; *p; p++) if(!strncmp(p, "s of ", 5)){
  1231. X            while(*p = p[1]) p++;
  1232. X            goto sing;
  1233. X        }
  1234. X        /* remove -s or -es (boxes) or -ies (rubies, zruties) */
  1235. X        p = eos(bp);
  1236. X        if(p[-1] == 's') {
  1237. X            if(p[-2] == 'e') {
  1238. X                if(p[-3] == 'i') {
  1239. X#ifdef KAA
  1240. X                    if(!strcmp(p-7, "cookies") || !strcmp(p-4, "pies"))
  1241. X#else
  1242. X                    if(!strcmp(p-7, "cookies"))
  1243. X#endif
  1244. X                        goto mins;
  1245. X                    Strcpy(p-3, "y");
  1246. X                    goto sing;
  1247. X                }
  1248. X
  1249. X                /* note: cloves / knives from clove / knife */
  1250. X                if(!strcmp(p-6, "knives")) {
  1251. X                    Strcpy(p-3, "fe");
  1252. X                    goto sing;
  1253. X                }
  1254. X
  1255. X                /* note: nurses, axes but boxes */
  1256. X                if(!strcmp(p-5, "boxes")) {
  1257. X                    p[-2] = 0;
  1258. X                    goto sing;
  1259. X                }
  1260. X            }
  1261. X        mins:
  1262. X            p[-1] = 0;
  1263. X        } else {
  1264. X            if(!strcmp(p-9, "homunculi")
  1265. X#ifdef KAA
  1266. X                || !strcmp(p-5, "fungi")
  1267. X#endif
  1268. X                            ) {
  1269. X                Strcpy(p-1, "us"); /* !! makes string longer */
  1270. X                goto sing;
  1271. X            }
  1272. X            if(!strcmp(p-5, "teeth")) {
  1273. X                Strcpy(p-5, "tooth");
  1274. X                goto sing;
  1275. X            }
  1276. X            /* here we cannot find the plural suffix */
  1277. X        }
  1278. X    }
  1279. Xsing:
  1280. X    if(!strcmp(bp, "amulet of yendor")) {
  1281. X        typ = AMULET_OF_YENDOR;
  1282. X        goto typfnd;
  1283. X    }
  1284. X    if(!strcmp(bp, "ring mail")){    /* Note: ring mail is not a ring ! */
  1285. X        let = ARMOR_SYM;
  1286. X        an = bp;
  1287. X        goto srch;
  1288. X    }
  1289. X
  1290. X    p = eos(bp);
  1291. X#ifdef KOPS    /* kluge to re-capitalize "dead Kop" */
  1292. X    if (!strcmp(p-3, "kop")) {
  1293. X        *(p-3) = 'K';
  1294. X        an = bp;
  1295. X        goto srch;
  1296. X    }
  1297. X#endif
  1298. X
  1299. X    for(i = 0; i < sizeof(wrpsym); i++) {
  1300. X        register int j = strlen(wrp[i]);
  1301. X        if(!strncmp(bp, wrp[i], j)){
  1302. X            let = wrpsym[i];
  1303. X            bp += j;
  1304. X            if(!strncmp(bp, " of ", 4)) an = bp+4;
  1305. X            /* else if(*bp) ?? */
  1306. X            goto srch;
  1307. X        }
  1308. X        if(!strcmp(p-j, wrp[i])){
  1309. X            let = wrpsym[i];
  1310. X            p -= j;
  1311. X            *p = 0;
  1312. X            if(p[-1] == ' ') p[-1] = 0;
  1313. X            dn = bp;
  1314. X            goto srch;
  1315. X        }
  1316. X    }
  1317. X    if(!strcmp(p-6, " stone")){
  1318. X        p[-6] = 0;
  1319. X        let = GEM_SYM;
  1320. X        an = bp;
  1321. X        goto srch;
  1322. X    }
  1323. X#ifdef KAA
  1324. X    if(!strcmp(p-10, "gold piece") || !strcmp(p-7, "zorkmid")) {
  1325. X        if (cnt > 5000) cnt=5000;
  1326. X        if (cnt < 1) cnt=1;
  1327. X        pline("%d gold piece%s.", cnt, cnt==1 ? "" : "s");
  1328. X        u.ugold += cnt;
  1329. X        flags.botl=1;
  1330. X        return(0);
  1331. X    }
  1332. X#endif
  1333. X    if(!strcmp(bp, "very heavy iron ball")){
  1334. X        heavy = 1;
  1335. X        typ = HEAVY_IRON_BALL;
  1336. X        goto typfnd;
  1337. X    }
  1338. X    an = bp;
  1339. Xsrch:
  1340. X    if(!an && !dn && !un)
  1341. X        goto any;
  1342. X    i = 1;
  1343. X    if(let) i = bases[letindex(let)];
  1344. X    while(i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)){
  1345. X        register char *zn = objects[i].oc_name;
  1346. X
  1347. X        if(!zn) goto nxti;
  1348. X        if(an && strcmp(an, zn))
  1349. X            goto nxti;
  1350. X        if(dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn)))
  1351. X            goto nxti;
  1352. X        if(un && (!(zn = objects[i].oc_uname) || strcmp(un, zn)))
  1353. X            goto nxti;
  1354. X        typ = i;
  1355. X        goto typfnd;
  1356. X    nxti:
  1357. X        i++;
  1358. X    }
  1359. Xany:
  1360. X    if(!let) let = wrpsym[rn2(sizeof(wrpsym))];
  1361. X    typ = probtype(let);
  1362. Xtypfnd:
  1363. X    { register struct obj *otmp;
  1364. X      extern struct obj *mksobj();
  1365. X    let = objects[typ].oc_olet;
  1366. X    otmp = mksobj(typ);
  1367. X    if(heavy)
  1368. X        otmp->owt += 15;
  1369. X    if(cnt > 0 && index("%?!*)", let) &&
  1370. X#ifdef KAA
  1371. X        (cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt <= 20)))
  1372. X#else
  1373. X        (cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20)))
  1374. X#endif
  1375. X        otmp->quan = cnt;
  1376. X
  1377. X    if(spe > 3 && spe > otmp->spe)
  1378. X        spe = 0;
  1379. X    else if(let == WAND_SYM)
  1380. X        spe = otmp->spe;
  1381. X#ifdef KAA
  1382. X    if(let==WEAPON_SYM && blessed) {
  1383. X        if(u.uluck < 0) otmp->cursed=1;
  1384. X        else otmp->dknown=1;
  1385. X    }
  1386. X#endif
  1387. X    if(spe == 3 && u.uluck < 0)
  1388. X        spesgn = -1;
  1389. X    if(let != WAND_SYM && spesgn == -1)
  1390. X        spe = -spe;
  1391. X    if(let == BALL_SYM)
  1392. X        spe = 0;
  1393. X    else if(let == AMULET_SYM)
  1394. X        spe = -1;
  1395. X    else if(typ == WAN_WISHING && rn2(10))
  1396. X        spe = (rn2(10) ? -1 : 0);
  1397. X#ifdef MARKER
  1398. X    else if(typ == MAGIC_MARKER)
  1399. X        spe = rn1(50,50);
  1400. X#endif
  1401. X    otmp->spe = spe;
  1402. X
  1403. X    if(spesgn == -1)
  1404. X        otmp->cursed = 1;
  1405. X
  1406. X    return(otmp);
  1407. X    }
  1408. X}
  1409. END_OF_objnam.c
  1410. if test 13414 -ne `wc -c <objnam.c`; then
  1411.     echo shar: \"objnam.c\" unpacked with wrong size!
  1412. fi
  1413. # end of overwriting check
  1414. fi
  1415. if test -f potion.c -a "${1}" != "-c" ; then 
  1416.   echo shar: Will not over-write existing file \"potion.c\"
  1417. else
  1418. echo shar: Extracting \"potion.c\" \(13424 characters\)
  1419. sed "s/^X//" >potion.c <<'END_OF_potion.c'
  1420. X/*    SCCS Id: @(#)potion.c    1.3    87/07/14
  1421. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  1422. X/* potion.c - version 1.0.3 */
  1423. X
  1424. X#include "hack.h"
  1425. Xextern int float_down();
  1426. Xextern char *nomovemsg;
  1427. Xextern struct monst youmonst;
  1428. Xextern struct monst *makemon();
  1429. Xchar *hcolor();
  1430. X#ifdef KAA
  1431. Xchar *xname();
  1432. Xextern char pl_character[];
  1433. X#endif
  1434. X#ifdef FOUNTAINS
  1435. Xextern int drinkfountain();
  1436. Xextern int dipfountain();
  1437. X#endif
  1438. X
  1439. Xint    nothing, unkn;
  1440. X
  1441. Xdodrink() {
  1442. X    register struct obj *otmp;
  1443. X    register int    retval;
  1444. X
  1445. X#ifdef FOUNTAINS
  1446. X
  1447. X      /* Is there something to drink here, i.e., a fountain? */
  1448. X       if (IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
  1449. X      pline("Drink from the fountain? [ny] ");
  1450. X      if(readchar() == 'y') {
  1451. X        (void) drinkfountain();
  1452. X        return(0);
  1453. X      }
  1454. X       }   
  1455. X
  1456. X#endif /* FOUNTAINS /**/
  1457. X
  1458. X    nothing = unkn = 0;
  1459. X    otmp = getobj("!", "drink");
  1460. X    if(!otmp) return(0);
  1461. X    if(!strcmp(objects[otmp->otyp].oc_descr, "smoky") && !rn2(13)) {
  1462. X        ghost_from_bottle();
  1463. X        goto use_it;
  1464. X    }
  1465. X    if((retval = peffects(otmp)) >= 0) return(retval);
  1466. X
  1467. X    if(nothing) {
  1468. X        unkn++;
  1469. X        pline("You have a %s feeling for a moment, then it passes.",
  1470. X          Hallucination ? "normal" : "peculiar");
  1471. X    }
  1472. X    if(otmp->dknown && !objects[otmp->otyp].oc_name_known) {
  1473. X        if(!unkn) {
  1474. X            objects[otmp->otyp].oc_name_known = 1;
  1475. X            more_experienced(0,10);
  1476. X        } else if(!objects[otmp->otyp].oc_uname)
  1477. X            docall(otmp);
  1478. X    }
  1479. Xuse_it:
  1480. X    useup(otmp);
  1481. X    return(1);
  1482. X}
  1483. X
  1484. Xpeffects(otmp)
  1485. X    register struct obj    *otmp;
  1486. X{
  1487. X    register struct obj    *objs;
  1488. X    register struct monst    *mtmp;
  1489. X
  1490. X    switch(otmp->otyp){
  1491. X    case POT_RESTORE_STRENGTH:
  1492. X#ifdef SPELLS
  1493. X    case SPE_RESTORE_STRENGTH:
  1494. X#endif
  1495. X        unkn++;
  1496. X        pline("Wow!  This makes you feel great!");
  1497. X        if(u.ustr < u.ustrmax) {
  1498. X            u.ustr = u.ustrmax;
  1499. X            flags.botl = 1;
  1500. X        }
  1501. X        break;
  1502. X#ifdef KAA
  1503. X    case POT_HALLUCINATION:
  1504. X        if (Hallucination) nothing++;
  1505. X        else pline("Oh wow!  Everything looks so cosmic!");
  1506. X        Hallucination += rn1(100,750);
  1507. X        setsee();
  1508. X        break;
  1509. X    case POT_HOLY_WATER:
  1510. X        unkn++;
  1511. X        if(index("VWZ&",u.usym)) {
  1512. X            pline("This burns like acid!");
  1513. X            losehp(d(2,6)); /* will never kill you */
  1514. X        } else {
  1515. X            pline("You feel full of awe.");
  1516. X            if (Sick) Sick=0;
  1517. X            if (HConfusion) HConfusion=0;
  1518. X        }
  1519. X#else
  1520. X    case POT_HOLY_WATER:
  1521. X    case POT_HALLUCINATION:
  1522. X#endif
  1523. X        break;
  1524. X    case POT_BOOZE:
  1525. X        unkn++;
  1526. X        pline("Ooph!  This tastes like liquid fire!");
  1527. X        HConfusion += d(3,8);
  1528. X        /* the whiskey makes us feel better */
  1529. X        if(u.uhp < u.uhpmax) losehp(-1, "bottle of whiskey");
  1530. X        if(!rn2(4)) {
  1531. X            pline("You pass out.");
  1532. X            multi = -rnd(15);
  1533. X            nomovemsg = "You awake with a headache.";
  1534. X        }
  1535. X        break;
  1536. X    case POT_INVISIBILITY:
  1537. X#ifdef SPELLS
  1538. X    case SPE_INVISIBILITY:
  1539. X#endif
  1540. X        if(Invis || See_invisible)
  1541. X          nothing++;
  1542. X        else {
  1543. X          if(!Blind)
  1544. X            pline("Gee!  All of a sudden, you can't see yourself.");
  1545. X          else
  1546. X            pline("You feel rather airy."), unkn++;
  1547. X          newsym(u.ux,u.uy);
  1548. X        }
  1549. X        HInvis += rn1(15,31);
  1550. X        break;
  1551. X    case POT_FRUIT_JUICE:
  1552. X        pline("This tastes like fruit juice.");
  1553. X        lesshungry(20);
  1554. X        break;
  1555. X    case POT_HEALING:
  1556. X        pline("You begin to feel better.");
  1557. X        healup(rnd(10), 1, 1, 1);
  1558. X        break;
  1559. X    case POT_PARALYSIS:
  1560. X        if(Levitation)
  1561. X            pline("You are motionlessly suspended.");
  1562. X        else
  1563. X            pline("Your feet are frozen to the floor!");
  1564. X        nomul(-(rn1(10,25)));
  1565. X        break;
  1566. X    case POT_MONSTER_DETECTION:
  1567. X#ifdef SPELLS
  1568. X    case SPE_DETECT_MONSTERS:
  1569. X#endif
  1570. X        if(!fmon) {
  1571. X            strange_feeling(otmp, "You feel threatened.");
  1572. X            return(1);
  1573. X        } else {
  1574. X            cls();
  1575. X            for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  1576. X                if(mtmp->mx > 0)
  1577. X                at(mtmp->mx,mtmp->my,Hallucination ? rndmonsym() :
  1578. X                mtmp->data->mlet);
  1579. X            prme();
  1580. X            pline("You sense the presence of monsters.");
  1581. X            more();
  1582. X            docrt();
  1583. X        }
  1584. X        break;
  1585. X    case POT_OBJECT_DETECTION:
  1586. X#ifdef SPELLS
  1587. X    case SPE_DETECT_TREASURE:
  1588. X#endif
  1589. X        if(!fobj) {
  1590. X            strange_feeling(otmp, "You feel a pull downward.");
  1591. X            return(1);
  1592. X        } else {
  1593. X            for(objs = fobj; objs; objs = objs->nobj)
  1594. X            if(objs->ox != u.ux || objs->oy != u.uy)
  1595. X                goto outobjmap;
  1596. X            pline("You sense the presence of objects close nearby.");
  1597. X            break;
  1598. X        outobjmap:
  1599. X            cls();
  1600. X            for(objs = fobj; objs; objs = objs->nobj)
  1601. X                at(objs->ox,objs->oy,Hallucination ? rndobjsym()
  1602. X                 : objs->olet);
  1603. X
  1604. X            /* monster possessions added by GAN 12/16/86 */
  1605. X            for(mtmp = fmon ; mtmp ; mtmp = mtmp->nmon)
  1606. X                if(mtmp->minvent)
  1607. X                    for(objs = mtmp->minvent; objs ;
  1608. X                        objs = objs->nobj)
  1609. X                        at(mtmp->mx,mtmp->my,objs->olet);
  1610. X            prme();
  1611. X            pline("You sense the presence of objects.");
  1612. X            more();
  1613. X            docrt();
  1614. X        }
  1615. X        break;
  1616. X    case POT_SICKNESS:
  1617. X        pline("Yech! This stuff tastes like poison.");
  1618. X        if(Poison_resistance)
  1619. X    pline("(But in fact it was biologically contaminated orange juice.)");
  1620. X#ifdef KAA
  1621. X        if (pl_character[0] == 'H')
  1622. X            pline("Fortunately you have been immunized!");
  1623. X        else {
  1624. X#endif
  1625. X            losestr(rn1(4,3));
  1626. X            losehp(rnd(10), "contaminated potion");
  1627. X#ifdef KAA
  1628. X        }
  1629. X#endif
  1630. X        if(Hallucination) {
  1631. X            pline("You are shocked back to your senses!");
  1632. X            Hallucination=1;
  1633. X        }
  1634. X        break;
  1635. X    case POT_CONFUSION:
  1636. X        if(!Confusion)
  1637. X            if (Hallucination) {
  1638. X            pline("What a trippy feeling!");
  1639. X            unkn++;
  1640. X            } else
  1641. X            pline("Huh, What?  Where am I?");
  1642. X        else    nothing++;
  1643. X        HConfusion += rn1(7,16);
  1644. X        break;
  1645. X    case POT_GAIN_STRENGTH:
  1646. X        pline("Wow do you feel strong!");
  1647. X        gainstr(0);
  1648. X        break;
  1649. X    case POT_SPEED:
  1650. X        if(Wounded_legs) {
  1651. X            heal_legs();
  1652. X            unkn++;
  1653. X            break;
  1654. X        }        /* and fall through */
  1655. X#ifdef SPELLS
  1656. X    case SPE_HASTE_SELF:
  1657. X#endif
  1658. X        if(!(Fast & ~INTRINSIC))
  1659. X            pline("You are suddenly moving much faster.");
  1660. X        else
  1661. X            pline("Your legs get new energy."), unkn++;
  1662. X        Fast += rn1(10,100);
  1663. X        break;
  1664. X    case POT_BLINDNESS:
  1665. X        if(!Blind)
  1666. X            if (Hallucination)
  1667. X                pline("Bummer!  Everything is dark!  Help!");
  1668. X            else 
  1669. X                pline("A cloud of darkness falls upon you.");
  1670. X        else    nothing++;
  1671. X        Blind += rn1(100,250);
  1672. X        seeoff(0);
  1673. X        break;
  1674. X    case POT_GAIN_LEVEL: 
  1675. X        pluslvl();
  1676. X        break;
  1677. X    case POT_EXTRA_HEALING:
  1678. X        pline("You feel much better.");
  1679. X        healup(d(2,20)+1, 2, 1, 1);
  1680. X        if(Hallucination) Hallucination = 1;
  1681. X        break;
  1682. X    case POT_LEVITATION:
  1683. X#ifdef SPELLS
  1684. X    case SPE_LEVITATION:
  1685. X#endif
  1686. X        if(!Levitation)
  1687. X            float_up();
  1688. X        else
  1689. X            nothing++;
  1690. X        Levitation += rnd(100);
  1691. X        u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down;
  1692. X        break;
  1693. X    case POT_GAIN_ENERGY:            /* M. Stephenson */
  1694. X#ifdef SPELLS
  1695. X        {    register int     num;
  1696. X            if(Confusion) {
  1697. X                pline("You feel feverish.");
  1698. X                unkn++;
  1699. X            } else
  1700. X                pline("Magical energies course through your body.");
  1701. X            num = rnd(5) + 1;
  1702. X            u.uenmax += num;
  1703. X            u.uen += num;
  1704. X            flags.botl = 1;
  1705. X            break;
  1706. X        }
  1707. X#else
  1708. X        pline("This potion tastes wierd!");
  1709. X        break;
  1710. X#endif
  1711. X    default:
  1712. X        impossible("What a funny potion! (%u)", otmp->otyp);
  1713. X        return(0);
  1714. X    }
  1715. X    return(-1);
  1716. X}
  1717. X
  1718. Xhealup(nhp, nxtra, curesick, cureblind)
  1719. X    int    nhp, nxtra;
  1720. X    register boolean curesick, cureblind;
  1721. X{
  1722. X#ifdef KAA
  1723. X    if (u.mtimedone & nhp) {
  1724. X        u.mh += rnd(nhp);
  1725. X        if (u.mh > u.mhmax) u.mh = ++u.mhmax;
  1726. X    }
  1727. X#endif
  1728. X    if(nhp)    {
  1729. X        u.uhp += nhp;
  1730. X        if(u.uhp > u.uhpmax)    u.uhp = (u.uhpmax += nxtra);
  1731. X    }
  1732. X    if(Blind && cureblind)    Blind = 1;    /* see on next move */
  1733. X    if(Sick && curesick)    Sick = 0;
  1734. X    flags.botl = 1;
  1735. X    return;
  1736. X}
  1737. X
  1738. Xpluslvl()
  1739. X{
  1740. X    register num;
  1741. X
  1742. X    pline("You feel more experienced.");
  1743. X    num = rnd(10);
  1744. X    u.uhpmax += num;
  1745. X    u.uhp += num;
  1746. X#ifdef SPELLS
  1747. X    num = rnd(u.ulevel/2+1) + 1;        /* M. Stephenson */
  1748. X    u.uenmax += num;
  1749. X    u.uen += num;
  1750. X#endif
  1751. X    if(u.ulevel < 14) {
  1752. X        extern long newuexp();
  1753. X
  1754. X        u.uexp = newuexp()+1;
  1755. X        pline("Welcome to experience level %u.", ++u.ulevel);
  1756. X    }
  1757. X    flags.botl = 1;
  1758. X}
  1759. X
  1760. Xstrange_feeling(obj,txt)
  1761. Xregister struct obj *obj;
  1762. Xregister char *txt;
  1763. X{
  1764. X    if(flags.beginner)
  1765. X        pline("You have a %s feeling for a moment, then it passes.",
  1766. X        Hallucination ? "normal" : "strange");
  1767. X    else
  1768. X        pline(txt);
  1769. X    if(!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
  1770. X        docall(obj);
  1771. X    useup(obj);
  1772. X}
  1773. X
  1774. Xchar *bottlenames[] = {
  1775. X    "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial"
  1776. X};
  1777. X
  1778. Xpotionhit(mon, obj)
  1779. Xregister struct monst *mon;
  1780. Xregister struct obj *obj;
  1781. X{
  1782. X    extern char *xname();
  1783. X    register char *botlnam = bottlenames[rn2(SIZE(bottlenames))];
  1784. X    boolean uclose, isyou = (mon == &youmonst);
  1785. X
  1786. X    if(isyou) {
  1787. X        uclose = TRUE;
  1788. X        pline("The %s crashes on your head and breaks into shivers.",
  1789. X            botlnam);
  1790. X        losehp(rnd(2), "thrown potion");
  1791. X    } else {
  1792. X        uclose = (dist(mon->mx,mon->my) < 3);
  1793. X        /* perhaps 'E' and 'a' have no head? */
  1794. X        pline("The %s crashes on %s's head and breaks into shivers.",
  1795. X            botlnam, monnam(mon));
  1796. X        if(rn2(5) && mon->mhp > 1)
  1797. X            mon->mhp--;
  1798. X    }
  1799. X    pline("The %s evaporates.", xname(obj));
  1800. X
  1801. X#ifdef KAA
  1802. X    if(!isyou) switch (obj->otyp) {
  1803. X#else
  1804. X    if(!isyou && !rn2(3)) switch(obj->otyp) {
  1805. X#endif
  1806. X
  1807. X    case POT_RESTORE_STRENGTH:
  1808. X    case POT_GAIN_STRENGTH:
  1809. X    case POT_HEALING:
  1810. X    case POT_EXTRA_HEALING:
  1811. X        if(mon->mhp < mon->mhpmax) {
  1812. X            mon->mhp = mon->mhpmax;
  1813. X            pline("%s looks sound and hale again!", Monnam(mon));
  1814. X        }
  1815. X        break;
  1816. X    case POT_SICKNESS:
  1817. X        if((mon->mhpmax > 3) && !resist(mon, '!', 0, NOTELL))
  1818. X            mon->mhpmax /= 2;
  1819. X        if((mon->mhp > 2) && !resist(mon, '!', 0, NOTELL))
  1820. X            mon->mhp /= 2;
  1821. X#ifdef KAA
  1822. X        pline("%s looks rather ill.", Monnam(mon));
  1823. X#endif
  1824. X        break;
  1825. X    case POT_CONFUSION:
  1826. X    case POT_BOOZE:
  1827. X        if(!resist(mon, '!', 0, NOTELL))  mon->mconf = 1;
  1828. X        break;
  1829. X    case POT_INVISIBILITY:
  1830. X        unpmon(mon);
  1831. X        mon->minvis = 1;
  1832. X        pmon(mon);
  1833. X        break;
  1834. X    case POT_PARALYSIS:
  1835. X        mon->mfroz = 1;
  1836. X        break;
  1837. X    case POT_SPEED:
  1838. X        mon->mspeed = MFAST;
  1839. X        break;
  1840. X    case POT_BLINDNESS:
  1841. X        mon->mblinded |= 64 + rn2(32) +
  1842. X                      rn2(32) * !resist(mon, '!', 0, NOTELL);
  1843. X        break;
  1844. X#ifdef KAA
  1845. X    case POT_HOLY_WATER:
  1846. X        if (index("ZVW &", mon->data->mlet)) {
  1847. X            pline("%s shrieks in pain!", Monnam(mon));
  1848. X            mon->mhp -= d(2,6);
  1849. X            if (mon->mhp <1) killed(mon);
  1850. X        }
  1851. X        break;
  1852. X#endif
  1853. X/*    
  1854. X    case POT_GAIN_LEVEL:
  1855. X    case POT_LEVITATION:
  1856. X    case POT_FRUIT_JUICE:
  1857. X    case POT_MONSTER_DETECTION:
  1858. X    case POT_OBJECT_DETECTION:
  1859. X        break;
  1860. X*/
  1861. X    }
  1862. X    if(uclose && rn2(5))
  1863. X        potionbreathe(obj);
  1864. X    obfree(obj, Null(obj));
  1865. X}
  1866. X
  1867. Xpotionbreathe(obj)
  1868. Xregister struct obj *obj;
  1869. X{
  1870. X    switch(obj->otyp) {
  1871. X    case POT_RESTORE_STRENGTH:
  1872. X    case POT_GAIN_STRENGTH:
  1873. X        if(u.ustr < u.ustrmax) u.ustr++, flags.botl = 1;
  1874. X        break;
  1875. X    case POT_HEALING:
  1876. X    case POT_EXTRA_HEALING:
  1877. X        if(u.uhp < u.uhpmax) u.uhp++, flags.botl = 1;
  1878. X        break;
  1879. X    case POT_SICKNESS:
  1880. X        if(u.uhp <= 5) u.uhp = 1; else u.uhp -= 5;
  1881. X        flags.botl = 1;
  1882. X        break;
  1883. X    case POT_HALLUCINATION:
  1884. X#ifdef KAA
  1885. X        pline("You have a vision for a moment.");
  1886. X        break;
  1887. X#endif
  1888. X    case POT_CONFUSION:
  1889. X    case POT_BOOZE:
  1890. X        if(!Confusion)
  1891. X            pline("You feel somewhat dizzy.");
  1892. X        HConfusion += rnd(5);
  1893. X        break;
  1894. X    case POT_INVISIBILITY:
  1895. X        pline("For an instant you couldn't see your right hand.");
  1896. X        break;
  1897. X    case POT_PARALYSIS:
  1898. X        pline("Something seems to be holding you.");
  1899. X        nomul(-rnd(5));
  1900. X        break;
  1901. X    case POT_SPEED:
  1902. X        Fast += rnd(5);
  1903. X        pline("Your knees seem more flexible now.");
  1904. X        break;
  1905. X    case POT_BLINDNESS:
  1906. X        if(!Blind) pline("It suddenly gets dark.");
  1907. X        Blind += rnd(5);
  1908. X        seeoff(0);
  1909. X        break;
  1910. X/*    
  1911. X    case POT_GAIN_LEVEL:
  1912. X    case POT_LEVITATION:
  1913. X    case POT_FRUIT_JUICE:
  1914. X    case POT_MONSTER_DETECTION:
  1915. X    case POT_OBJECT_DETECTION:
  1916. X        break;
  1917. X*/
  1918. X    }
  1919. X    /* note: no obfree() */
  1920. X}
  1921. X
  1922. X/*
  1923. X * -- rudimentary -- to do this correctly requires much more work
  1924. X * -- all sharp weapons get one or more qualities derived from the potions
  1925. X * -- texts on scrolls may be (partially) wiped out; do they become blank?
  1926. X * --   or does their effect change, like under Confusion?
  1927. X * -- all objects may be made invisible by POT_INVISIBILITY
  1928. X * -- If the flask is small, can one dip a large object? Does it magically
  1929. X * --   become a jug? Etc.
  1930. X */
  1931. Xdodip(){
  1932. X    register struct obj *potion, *obj;
  1933. X#ifdef KAA
  1934. X    char *tmp;
  1935. X#endif
  1936. X
  1937. X    if(!(obj = getobj("#", "dip")))
  1938. X        return(0);
  1939. X#ifdef FOUNTAINS
  1940. X    /* Is there something to dip into here, i.e., a fountain? */
  1941. X    if (levl[u.ux][u.uy].typ == FOUNTAIN) {
  1942. X        pline("Dip it in the fountain? [ny] ");
  1943. X        if(readchar() == 'y') {
  1944. X            dipfountain(obj);
  1945. X            return(1);
  1946. X        }
  1947. X    }
  1948. X#endif
  1949. X    if(!(potion = getobj("!", "dip into")))
  1950. X        return(0);
  1951. X#ifndef KAA
  1952. X    pline("Interesting...");
  1953. X#else
  1954. X    if(potion->otyp == POT_HOLY_WATER) {
  1955. X        if (obj->cursed) {
  1956. X            obj->cursed=0;
  1957. X            pline("Your %s %s.", aobjnam(obj,"softly glow"), 
  1958. X            Hallucination ? hcolor() : "amber");
  1959. X    poof:    useup(potion);
  1960. X            return(1);
  1961. X        } else if(obj->otyp >= ARROW && obj->otyp <= SPEAR) {
  1962. X            obj->dknown=1;
  1963. X            tmp = Hallucination ? hcolor() : "light blue";
  1964. X    /* dknown for weapons is meaningless, so it's free to be reused. */
  1965. X            pline("Your %s with a%s %s aura.", aobjnam(obj,"softly glow"),
  1966. X            index("aeiou",*tmp) ? "n" : "", tmp);
  1967. X            goto poof;
  1968. X        }
  1969. X    }
  1970. X#endif
  1971. X    if(obj->otyp == ARROW || obj->otyp == DART ||
  1972. X       obj->otyp == CROSSBOW_BOLT || obj->otyp == SHURIKEN) {
  1973. X        if(potion->otyp == POT_SICKNESS) {
  1974. X            char buf[BUFSZ];
  1975. X            useup(potion);
  1976. X            if(obj->spe < 7) obj->spe++;    /* %% */
  1977. X            sprintf(buf, xname(potion));
  1978. X            pline("The %s forms a coating on the %s.",
  1979. X                buf, xname(obj));
  1980. X        }
  1981. X    }
  1982. X#ifdef KAA
  1983. X    pline("Interesting...");
  1984. X#endif
  1985. X    return(1);
  1986. X}
  1987. X
  1988. Xghost_from_bottle(){
  1989. X    extern struct permonst pm_ghost;
  1990. X    register struct monst *mtmp;
  1991. X
  1992. X    if(!(mtmp = makemon(PM_GHOST,u.ux,u.uy))){
  1993. X        pline("This bottle turns out to be empty.");
  1994. X        return;
  1995. X    }
  1996. X    mnexto(mtmp);
  1997. X    pline("As you open the bottle, an enormous ghost emerges!");
  1998. X    pline("You are frightened to death, and unable to move.");
  1999. X    nomul(-3);
  2000. X}
  2001. X
  2002. Xgainstr(inc)
  2003. Xregister int    inc;
  2004. X{
  2005. X    if(u.ustr >= 118) return;    /* > 118 is impossible */
  2006. X
  2007. X    if((u.ustr > 17) && !inc)    u.ustr += rnd(118 - u.ustr);
  2008. X#ifdef HARD
  2009. X    else                u.ustr++;
  2010. X#else 
  2011. X    else                u.ustr += (inc) ? 1 : rnd(3);
  2012. X#endif
  2013. X
  2014. X    if(u.ustr > u.ustrmax)        u.ustrmax = u.ustr;
  2015. X    flags.botl = 1;
  2016. X}
  2017. END_OF_potion.c
  2018. if test 13424 -ne `wc -c <potion.c`; then
  2019.     echo shar: \"potion.c\" unpacked with wrong size!
  2020. fi
  2021. # end of overwriting check
  2022. fi
  2023. if test -f unixunix.c -a "${1}" != "-c" ; then 
  2024.   echo shar: Will not over-write existing file \"unixunix.c\"
  2025. else
  2026. echo shar: Extracting \"unixunix.c\" \(10405 characters\)
  2027. sed "s/^X//" >unixunix.c <<'END_OF_unixunix.c'
  2028. X/*    SCCS Id: @(#)unixunix.c    1.3    87/07/14
  2029. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  2030. X/* hack.unix.c - version 1.0.3 */
  2031. X
  2032. X/* This file collects some Unix dependencies; pager.c contains some more */
  2033. X
  2034. X/*
  2035. X * The time is used for:
  2036. X *    - seed for rand()
  2037. X *    - year on tombstone and yymmdd in record file
  2038. X *    - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
  2039. X *    - night and midnight (the undead are dangerous at midnight)
  2040. X *    - determination of what files are "very old"
  2041. X */
  2042. X
  2043. X#include <stdio.h>
  2044. X#include <errno.h>
  2045. X#include "hack.h"    /* mainly for index() which depends on BSD */
  2046. X
  2047. X#include    <sys/types.h>        /* for time_t and stat */
  2048. X#include    <sys/stat.h>
  2049. X#ifdef BSD
  2050. X#include    <sys/time.h>
  2051. X#else
  2052. X#include    <time.h>
  2053. X#endif
  2054. X
  2055. Xextern char *getenv();
  2056. Xextern time_t time();
  2057. X
  2058. Xsetrandom()
  2059. X{
  2060. X    (void) srand((int) time ((time_t *) 0));
  2061. X}
  2062. X
  2063. Xstruct tm *
  2064. Xgetlt()
  2065. X{
  2066. X    time_t date;
  2067. X    struct tm *localtime();
  2068. X
  2069. X    (void) time(&date);
  2070. X    return(localtime(&date));
  2071. X}
  2072. X
  2073. Xgetyear()
  2074. X{
  2075. X    return(1900 + getlt()->tm_year);
  2076. X}
  2077. X
  2078. Xchar *
  2079. Xgetdate()
  2080. X{
  2081. X    static char datestr[7];
  2082. X    register struct tm *lt = getlt();
  2083. X
  2084. X    (void) sprintf(datestr, "%2d%2d%2d",
  2085. X        lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
  2086. X    if(datestr[2] == ' ') datestr[2] = '0';
  2087. X    if(datestr[4] == ' ') datestr[4] = '0';
  2088. X    return(datestr);
  2089. X}
  2090. X
  2091. Xphase_of_the_moon()            /* 0-7, with 0: new, 4: full */
  2092. X{                    /* moon period: 29.5306 days */
  2093. X                    /* year: 365.2422 days */
  2094. X    register struct tm *lt = getlt();
  2095. X    register int epact, diy, golden;
  2096. X
  2097. X    diy = lt->tm_yday;
  2098. X    golden = (lt->tm_year % 19) + 1;
  2099. X    epact = (11 * golden + 18) % 30;
  2100. X    if ((epact == 25 && golden > 11) || epact == 24)
  2101. X        epact++;
  2102. X
  2103. X    return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
  2104. X}
  2105. X
  2106. Xnight()
  2107. X{
  2108. X    register int hour = getlt()->tm_hour;
  2109. X
  2110. X    return(hour < 6 || hour > 21);
  2111. X}
  2112. X
  2113. Xmidnight()
  2114. X{
  2115. X    return(getlt()->tm_hour == 0);
  2116. X}
  2117. X
  2118. Xstruct stat buf, hbuf;
  2119. X
  2120. Xgethdate(name) char *name; {
  2121. X/* old version - for people short of space */
  2122. X/*
  2123. X/* register char *np;
  2124. X/*    if(stat(name, &hbuf))
  2125. X/*        error("Cannot get status of %s.",
  2126. X/*            (np = rindex(name, '/')) ? np+1 : name);
  2127. X/*
  2128. X/* version using PATH from: seismo!gregc@ucsf-cgl.ARPA (Greg Couch) */
  2129. X
  2130. X
  2131. X/*
  2132. X * The problem with   #include    <sys/param.h>   is that this include file
  2133. X * does not exist on all systems, and moreover, that it sometimes includes
  2134. X * <sys/types.h> again, so that the compiler sees these typedefs twice.
  2135. X */
  2136. X#define        MAXPATHLEN    1024
  2137. X
  2138. Xregister char *np, *path;
  2139. Xchar filename[MAXPATHLEN+1];
  2140. X    if (index(name, '/') != NULL || (path = getenv("PATH")) == NULL)
  2141. X        path = "";
  2142. X
  2143. X    for (;;) {
  2144. X        if ((np = index(path, ':')) == NULL)
  2145. X            np = path + strlen(path);    /* point to end str */
  2146. X        if (np - path <= 1)            /* %% */
  2147. X            (void) strcpy(filename, name);
  2148. X        else {
  2149. X            (void) strncpy(filename, path, np - path);
  2150. X            filename[np - path] = '/';
  2151. X            (void) strcpy(filename + (np - path) + 1, name);
  2152. X        }
  2153. X        if (stat(filename, &hbuf) == 0)
  2154. X            return;
  2155. X        if (*np == '\0')
  2156. X            break;
  2157. X        path = np + 1;
  2158. X    }
  2159. X    error("Cannot get status of %s.",
  2160. X        (np = rindex(name, '/')) ? np+1 : name);
  2161. X}
  2162. X
  2163. Xuptodate(fd) {
  2164. X    if(fstat(fd, &buf)) {
  2165. X        pline("Cannot get status of saved level? ");
  2166. X        return(0);
  2167. X    }
  2168. X    if(buf.st_mtime < hbuf.st_mtime) {
  2169. X        pline("Saved level is out of date. ");
  2170. X        return(0);
  2171. X    }
  2172. X    return(1);
  2173. X}
  2174. X
  2175. X/* see whether we should throw away this xlock file */
  2176. Xveryold(fd) {
  2177. X    register int i;
  2178. X    time_t date;
  2179. X
  2180. X    if(fstat(fd, &buf)) return(0);            /* cannot get status */
  2181. X    if(buf.st_size != sizeof(int)) return(0);    /* not an xlock file */
  2182. X    (void) time(&date);
  2183. X    if(date - buf.st_mtime < 3L*24L*60L*60L) {    /* recent */
  2184. X        extern int errno;
  2185. X        int lockedpid;    /* should be the same size as hackpid */
  2186. X
  2187. X        if(read(fd, (char *)&lockedpid, sizeof(lockedpid)) !=
  2188. X            sizeof(lockedpid))
  2189. X            /* strange ... */
  2190. X            return(0);
  2191. X
  2192. X        /* From: Rick Adams <seismo!rick>
  2193. X        /* This will work on 4.1cbsd, 4.2bsd and system 3? & 5.
  2194. X        /* It will do nothing on V7 or 4.1bsd. */
  2195. X        if(!(kill(lockedpid, 0) == -1 && errno == ESRCH))
  2196. X            return(0);
  2197. X    }
  2198. X    (void) close(fd);
  2199. X    for(i = 1; i <= MAXLEVEL; i++) {        /* try to remove all */
  2200. X        glo(i);
  2201. X        (void) unlink(lock);
  2202. X    }
  2203. X    glo(0);
  2204. X    if(unlink(lock)) return(0);            /* cannot remove it */
  2205. X    return(1);                    /* success! */
  2206. X}
  2207. X
  2208. Xgetlock()
  2209. X{
  2210. X    extern int errno, hackpid, locknum;
  2211. X    register int i = 0, fd;
  2212. X
  2213. X    (void) fflush(stdout);
  2214. X
  2215. X    /* we ignore QUIT and INT at this point */
  2216. X    if (link(HLOCK, LLOCK) == -1) {
  2217. X        register int errnosv = errno;
  2218. X
  2219. X        perror(HLOCK);
  2220. X        printf("Cannot link %s to %s\n", LLOCK, HLOCK);
  2221. X        switch(errnosv) {
  2222. X        case ENOENT:
  2223. X            printf("Perhaps there is no (empty) file %s ?\n", HLOCK);
  2224. X            break;
  2225. X        case EACCES:
  2226. X            printf("It seems you don't have write permission here.\n");
  2227. X            break;
  2228. X        case EEXIST:
  2229. X            printf("(Try again or rm %s.)\n", LLOCK);
  2230. X            break;
  2231. X        default:
  2232. X            printf("I don't know what is wrong.");
  2233. X        }
  2234. X        getret();
  2235. X        error("");
  2236. X        /*NOTREACHED*/
  2237. X    }
  2238. X
  2239. X    regularize(lock);
  2240. X    glo(0);
  2241. X    if(locknum > 25) locknum = 25;
  2242. X
  2243. X    do {
  2244. X        if(locknum) lock[0] = 'a' + i++;
  2245. X
  2246. X        if((fd = open(lock, 0)) == -1) {
  2247. X            if(errno == ENOENT) goto gotlock;    /* no such file */
  2248. X            perror(lock);
  2249. X            (void) unlink(LLOCK);
  2250. X            error("Cannot open %s", lock);
  2251. X        }
  2252. X
  2253. X        if(veryold(fd))    /* if true, this closes fd and unlinks lock */
  2254. X            goto gotlock;
  2255. X        (void) close(fd);
  2256. X    } while(i < locknum);
  2257. X
  2258. X    (void) unlink(LLOCK);
  2259. X    error(locknum ? "Too many hacks running now."
  2260. X              : "There is a game in progress under your name.");
  2261. Xgotlock:
  2262. X    fd = creat(lock, FMASK);
  2263. X    if(unlink(LLOCK) == -1)
  2264. X        error("Cannot unlink %s.", LLOCK);
  2265. X    if(fd == -1) {
  2266. X        error("cannot creat lock file.");
  2267. X    } else {
  2268. X        if(write(fd, (char *) &hackpid, sizeof(hackpid))
  2269. X            != sizeof(hackpid)){
  2270. X            error("cannot write lock");
  2271. X        }
  2272. X        if(close(fd) == -1) {
  2273. X            error("cannot close lock");
  2274. X        }
  2275. X    }
  2276. X}    
  2277. X
  2278. X#ifdef MAIL
  2279. X
  2280. X/*
  2281. X * Notify user when new mail has arrived. [Idea from Merlyn Leroy, but
  2282. X * I don't know the details of his implementation.]
  2283. X * { Later note: he disliked my calling a general mailreader and felt that
  2284. X *   hack should do the paging itself. But when I get mail, I want to put it
  2285. X *   in some folder, reply, etc. - it would be unreasonable to put all these
  2286. X *   functions in hack. }
  2287. X * The mail daemon '2' is at present not a real monster, but only a visual
  2288. X * effect. Thus, makemon() is superfluous. This might become otherwise,
  2289. X * however. The motion of '2' is less restrained than usual: diagonal moves
  2290. X * from a DOOR are possible. He might also use SDOOR's. Also, '2' is visible
  2291. X * in a ROOM, even when you are Blind.
  2292. X * Its path should be longer when you are Telepat-hic and Blind.
  2293. X *
  2294. X * Interesting side effects:
  2295. X *    - You can get rich by sending yourself a lot of mail and selling
  2296. X *      it to the shopkeeper. Unfortunately mail isn't very valuable.
  2297. X *    - You might die in case '2' comes along at a critical moment during
  2298. X *      a fight and delivers a scroll the weight of which causes you to
  2299. X *      collapse.
  2300. X *
  2301. X * Possible extensions:
  2302. X *    - Open the file MAIL and do fstat instead of stat for efficiency.
  2303. X *      (But sh uses stat, so this cannot be too bad.)
  2304. X *    - Examine the mail and produce a scroll of mail called "From somebody".
  2305. X *    - Invoke MAILREADER in such a way that only this single letter is read.
  2306. X *
  2307. X *    - Make him lose his mail when a Nymph steals the letter.
  2308. X *    - Do something to the text when the scroll is enchanted or cancelled.
  2309. X */
  2310. X#include    "mkroom.h"
  2311. Xstatic struct stat omstat,nmstat;
  2312. Xstatic char *mailbox;
  2313. Xstatic long laststattime;
  2314. X
  2315. Xgetmailstatus() {
  2316. X    if(!(mailbox = getenv("MAIL")))
  2317. X        return;
  2318. X    if(stat(mailbox, &omstat)){
  2319. X#ifdef PERMANENT_MAILBOX
  2320. X        pline("Cannot get status of MAIL=%s .", mailbox);
  2321. X        mailbox = 0;
  2322. X#else
  2323. X        omstat.st_mtime = 0;
  2324. X#endif
  2325. X    }
  2326. X}
  2327. X
  2328. Xckmailstatus() {
  2329. X    if(!mailbox
  2330. X#ifdef MAILCKFREQ
  2331. X            || moves < laststattime + MAILCKFREQ
  2332. X#endif
  2333. X                            )
  2334. X        return;
  2335. X    laststattime = moves;
  2336. X    if(stat(mailbox, &nmstat)){
  2337. X#ifdef PERMANENT_MAILBOX
  2338. X        pline("Cannot get status of MAIL=%s anymore.", mailbox);
  2339. X        mailbox = 0;
  2340. X#else
  2341. X        nmstat.st_mtime = 0;
  2342. X#endif
  2343. X    } else if(nmstat.st_mtime > omstat.st_mtime) {
  2344. X        if(nmstat.st_size)
  2345. X            newmail();
  2346. X        getmailstatus();    /* might be too late ... */
  2347. X    }
  2348. X}
  2349. X
  2350. Xnewmail() {
  2351. X    /* produce a scroll of mail */
  2352. X    register struct obj *obj;
  2353. X    register struct monst *md;
  2354. X    extern char plname[];
  2355. X    extern struct obj *mksobj(), *addinv();
  2356. X    extern struct monst *makemon();
  2357. X    extern struct permonst pm_mail_daemon;
  2358. X
  2359. X    obj = mksobj(SCR_MAIL);
  2360. X    if(md = makemon(&pm_mail_daemon, u.ux, u.uy)) /* always succeeds */
  2361. X        mdrush(md,0);
  2362. X
  2363. X    pline("\"Hello, %s! I have some mail for you.\"", plname);
  2364. X    if(md) {
  2365. X        if(dist(md->mx,md->my) > 2)
  2366. X            pline("\"Catch!\"");
  2367. X        more();
  2368. X
  2369. X        /* let him disappear again */
  2370. X        mdrush(md,1);
  2371. X        mondead(md);
  2372. X    }
  2373. X
  2374. X    obj = addinv(obj);
  2375. X    (void) identify(obj);        /* set known and do prinv() */
  2376. X}
  2377. X
  2378. X/* make md run through the cave */
  2379. Xmdrush(md,away)
  2380. Xregister struct monst *md;
  2381. Xboolean away;
  2382. X{
  2383. X    register int uroom = inroom(u.ux, u.uy);
  2384. X    if(uroom >= 0) {
  2385. X        register int tmp = rooms[uroom].fdoor;
  2386. X        register int cnt = rooms[uroom].doorct;
  2387. X        register int fx = u.ux, fy = u.uy;
  2388. X        while(cnt--) {
  2389. X            if(dist(fx,fy) < dist(doors[tmp].x, doors[tmp].y)){
  2390. X                fx = doors[tmp].x;
  2391. X                fy = doors[tmp].y;
  2392. X            }
  2393. X            tmp++;
  2394. X        }
  2395. X        tmp_at(-1, md->data->mlet);    /* open call */
  2396. X        if(away) {    /* interchange origin and destination */
  2397. X            unpmon(md);
  2398. X            tmp = fx; fx = md->mx; md->mx = tmp;
  2399. X            tmp = fy; fy = md->my; md->my = tmp;
  2400. X        }
  2401. X        while(fx != md->mx || fy != md->my) {
  2402. X            register int dx,dy,nfx = fx,nfy = fy,d1,d2;
  2403. X
  2404. X            tmp_at(fx,fy);
  2405. X            d1 = DIST(fx,fy,md->mx,md->my);
  2406. X            for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
  2407. X                if(dx || dy) {
  2408. X                d2 = DIST(fx+dx,fy+dy,md->mx,md->my);
  2409. X                if(d2 < d1) {
  2410. X                    d1 = d2;
  2411. X                    nfx = fx+dx;
  2412. X                    nfy = fy+dy;
  2413. X                }
  2414. X                }
  2415. X            if(nfx != fx || nfy != fy) {
  2416. X                fx = nfx;
  2417. X                fy = nfy;
  2418. X            } else {
  2419. X                if(!away) {
  2420. X                md->mx = fx;
  2421. X                md->my = fy;
  2422. X                }
  2423. X                break;
  2424. X            } 
  2425. X        }
  2426. X        tmp_at(-1,-1);            /* close call */
  2427. X    }
  2428. X    if(!away)
  2429. X        pmon(md);
  2430. X}
  2431. X
  2432. Xreadmail() {
  2433. X#ifdef DEF_MAILREADER            /* This implies that UNIX is defined */
  2434. X    register char *mr = 0;
  2435. X    more();
  2436. X    if(!(mr = getenv("MAILREADER")))
  2437. X        mr = DEF_MAILREADER;
  2438. X    if(child(1)){
  2439. X        execl(mr, mr, (char *) 0);
  2440. X        exit(1);
  2441. X    }
  2442. X#else
  2443. X    (void) page_file(mailbox, FALSE);
  2444. X#endif
  2445. X    /* get new stat; not entirely correct: there is a small time
  2446. X       window where we do not see new mail */
  2447. X    getmailstatus();
  2448. X}
  2449. X#endif /* MAIL /**/
  2450. X
  2451. Xregularize(s)    /* normalize file name - we don't like ..'s or /'s */
  2452. Xregister char *s;
  2453. X{
  2454. X    register char *lp;
  2455. X
  2456. X    while((lp = index(s, '.')) || (lp = index(s, '/')))
  2457. X        *lp = '_';
  2458. X}
  2459. END_OF_unixunix.c
  2460. if test 10405 -ne `wc -c <unixunix.c`; then
  2461.     echo shar: \"unixunix.c\" unpacked with wrong size!
  2462. fi
  2463. # end of overwriting check
  2464. fi
  2465. echo shar: End of archive 7 \(of 16\).
  2466. cp /dev/null ark7isdone
  2467. MISSING=""
  2468. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
  2469.     if test ! -f ark${I}isdone ; then
  2470.     MISSING="${MISSING} ${I}"
  2471.     fi
  2472. done
  2473. if test "${MISSING}" = "" ; then
  2474.     echo You have unpacked all 16 archives.
  2475.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2476. else
  2477.     echo You still need to unpack the following archives:
  2478.     echo "        " ${MISSING}
  2479. fi
  2480. ##  End of shell archive.
  2481. exit 0
  2482.